package com.universest.swordholder.data.repository

import android.util.Log
import androidx.room.withTransaction
import com.universest.swordholder.data.UserDatabase
import com.universest.swordholder.data.dao.Passage
import com.universest.swordholder.data.dao.PassageDao
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.firstOrNull

class PassageRepository(val database: UserDatabase) {

    private val passageDao: PassageDao = database.passageDao()

    fun getPassageById(passageId: Int): Flow<Passage?> {
        return passageDao.getPassageById(passageId)
    }

    fun getPassagesByBookIdAndVolumeId(bookId: Int, volumeId: Int): Flow<List<Passage>>{
        return passageDao.getPassagesByBookIdAndVolumeId(bookId, volumeId)
    }

    fun getPassagesByBookId(bookId: Int): Flow<List<Passage>> {
        return passageDao.getPassagesByBookId(bookId)
    }

    fun getAllPassages(): Flow<List<Passage>> {
        return passageDao.getAllPassages()
    }

    suspend fun insert(passage: Passage) : Long{
        return passageDao.insert(passage)
    }

    suspend fun update(passage: Passage) {
        passageDao.update(passage)
    }

    suspend fun delete(passage: Passage) {
        passageDao.delete(passage)
    }

    suspend fun deleteById(passageId: Int) {
        passageDao.deleteById(passageId)
    }

    suspend fun deleteByBookId(bookId: Int) {
        passageDao.deleteByBookId(bookId)
    }

    fun getPassageCountByBookId(bookId: Int): Flow<Int> {
        return passageDao.getPassageCountByBookId(bookId)
    }

    suspend fun movePassageToAnotherVolume(passageId: Int, volumeId: Int,top: Boolean) {
        database.withTransaction {
            try {
                val passage = passageDao.getPassageById(passageId).firstOrNull()
                if (passage == null) return@withTransaction
                if (passage.volumeId == volumeId) return@withTransaction
                val comparePassage = (if(top) passageDao.getFirstPassageByBookIdAndVolumeId(passage.bookId, volumeId)
                else passageDao.getLastPassageByBookIdAndVolumeId(passage.bookId, volumeId)).firstOrNull()
                val order =  if(comparePassage == null){
                    0
                }else if(top){
                    comparePassage.order - 10
                }else{
                    comparePassage.order + 10
                }
                passageDao.update(passage.copy(volumeId = volumeId, order = order))
            }catch (e: Exception){
                Log.e("PassageRepository", "movePassageToAnotherVolume error: $e")
                throw e
            }
        }
    }
    suspend fun swapPassageOrder(passageIdA: Int, passageIdB: Int) {
        database.withTransaction {
            try {
                val passageA = passageDao.getPassageById(passageIdA).firstOrNull()
                val passageB = passageDao.getPassageById(passageIdB).firstOrNull()

                if (passageA == null || passageB == null) return@withTransaction
                if (passageA.bookId != passageB.bookId || passageA.volumeId != passageB.volumeId) return@withTransaction

                if (passageA.order == passageB.order) {
                    //兜底逻辑
                    val passages = passageDao.getPassagesByBookIdAndVolumeId(passageA.bookId, passageA.volumeId)
                        .firstOrNull()?.toMutableList()
                        ?: return@withTransaction

                    val indexA = passages.indexOfFirst { it.passageId == passageIdA }
                    val indexB = passages.indexOfFirst { it.passageId == passageIdB }

                    if (indexA == -1 || indexB == -1) return@withTransaction

                    // 交换 order
                    val tempOrder = passages[indexA].order
                    passages[indexA] = passages[indexA].copy(order = passages[indexB].order)
                    passages[indexB] = passages[indexB].copy(order = tempOrder)

                    // 更新所有顺序
                    passages.forEachIndexed { index, passage ->
                        val newOrder = index * 10 + 1
                        if (passage.order != newOrder) {
                            passageDao.update(passage.copy(order = newOrder))
                        }
                    }
                } else {
                    // 直接交换 order
                    passageDao.update(passageA.copy(order = passageB.order))
                    passageDao.update(passageB.copy(order = passageA.order))
                }
            } catch (e: Exception) {
                Log.e("PassageRepository", "swapPassageOrder error: $e")
                throw e
            }
        }
    }


    /**
     * 将一个章节移动到指定位置之后
     *
     * @param passageId 要移动的章节ID
     * @param afterPassageId 插入目标位置之后的章节ID，如果为null则表示移到最后
     */
    suspend fun movePassage(passageId: Int, afterPassageId: Int?) {
        // 如果目标位置就是自身，则无需操作
        if (afterPassageId == passageId) return

        database.withTransaction {
            try {
                // 在数据库事务内执行实际移动逻辑
                movePassageInternal(passageId, afterPassageId)
            } catch (e: Exception) {
                // 记录错误日志并重新抛出异常以触发事务回滚
                Log.e("PassageRepository", "movePassageInternal error: $e")
                throw e
            }
        }
    }

    /**
     * 实际执行章节移动的操作
     *
     * @param passageId 需要被移动的章节ID
     * @param afterPassageId 目标位置后面的章节ID（可为空）
     */
    private suspend fun movePassageInternal(passageId: Int, afterPassageId: Int?) {
        // 获取要移动的章节对象
        val passage = getPassageById(passageId).firstOrNull()
        if (passage == null) {
            Log.e("PassageRepository", "movePassage: passage not found")
            return
        }

        // 获取目标位置后的章节对象（如果存在）
        val afterPassage = afterPassageId?.let {
            passageDao.getPassageById(it).firstOrNull()
        }

        // 根据不同情况调用不同的处理函数
        when {
            // 情况1: 移动到卷末尾
            afterPassage == null -> moveToEnd(passage)

            // 情况2: 移动到卷开头
            isMovingToBeginning(passage, afterPassage) -> moveToBeginning(passage, afterPassage)

            // 情况3: 中间插入且有足够的空间
            hasSpaceBetween(passage, afterPassage) -> insertInMiddle(passage, afterPassage)

            // 情况4: 中间插入但没有足够空间，需要调整顺序
            else -> rearrangePassages(passage, afterPassage)
        }
    }

    /**
     * 将章节移动至其所在卷的末尾
     *
     * @param passage 待移动的章节对象
     */
    private suspend fun moveToEnd(passage: Passage) {
        // 查找当前卷中除了自己以外最大的order值
        val lastPassage = passageDao.getPassageWithMaxOrderInVolume(
            volumeId = passage.volumeId,
            exclude = passage.passageId
        ).firstOrNull()

        // 新的位置是最大order+10，如果没有其他章节则是0
        val newOrder = if (lastPassage == null) 0 else lastPassage.order + 10
        passageDao.update(passage.copy(order = newOrder))
    }

    /**
     * 判断是否将章节移动到了卷的最前面
     *
     * @param passage 待移动的章节
     * @param afterPassage 目标位置后的章节
     * @return 是否应该放在开头
     */
    private suspend fun isMovingToBeginning(passage: Passage, afterPassage: Passage): Boolean {
        // 查找目标位置前是否有章节
        val beforePassage = passageDao.getLastPassageBeforeOrderInVolume(
            volumeId = afterPassage.volumeId,
            order = afterPassage.order,
            exclude = passage.passageId
        ).firstOrNull()

        // 若无前置章节，则应放在开头
        return beforePassage == null
    }

    /**
     * 将章节放置在卷首部
     *
     * @param passage 待移动的章节
     * @param afterPassage 目标位置后的章节
     */
    private suspend fun moveToBeginning(passage: Passage, afterPassage: Passage) {
        // 放置在目标位置之前，并设置新order值
        val newOrder = afterPassage.order - 10
        passageDao.update(passage.copy(order = newOrder, volumeId = afterPassage.volumeId))
    }

    /**
     * 判断两个相邻章节之间是否存在足够的空间来插入新的章节
     *
     * @param passage 待移动的章节
     * @param afterPassage 目标位置后的章节
     * @return 是否有足够空间插入
     */
    private suspend fun hasSpaceBetween(passage: Passage, afterPassage: Passage): Boolean {
        // 找到目标位置之前的章节
        val beforePassage = passageDao.getLastPassageBeforeOrderInVolume(
            volumeId = afterPassage.volumeId,
            order = afterPassage.order,
            exclude = passage.passageId
        ).firstOrNull()

        // 判断中间是否有至少一个单位的空间
        return beforePassage != null && beforePassage.order < afterPassage.order - 1
    }

    /**
     * 在已有章节之间的空隙中插入新章节
     *
     * @param passage 待移动的章节
     * @param afterPassage 目标位置后的章节
     */
    private suspend fun insertInMiddle(passage: Passage, afterPassage: Passage) {
        // 找到目标位置之前的章节
        val beforePassage = passageDao.getLastPassageBeforeOrderInVolume(
            volumeId = afterPassage.volumeId,
            order = afterPassage.order,
            exclude = passage.passageId
        ).firstOrNull()!!

        // 取前后两章order的平均数作为新位置
        val newOrder = (beforePassage.order + afterPassage.order) / 2
        passageDao.update(passage.copy(order = newOrder, volumeId = afterPassage.volumeId))
    }

    /**
     * 当无法简单插入时，需要对一系列连续章节进行重新排序
     *
     * @param passage 待移动的章节
     * @param afterPassage 目标位置后的章节
     */
    private suspend fun rearrangePassages(passage: Passage, afterPassage: Passage) {
        // 先更新待移动章节的order为紧接afterPassage之后
        passageDao.update(passage.copy(order = afterPassage.order, volumeId = afterPassage.volumeId))

        // 开始依次向后调整后续章节的order值
        var currentPassage = afterPassage
        var currentOrder = afterPassage.order + 10

        while (true) {
            // 寻找下一个章节
            val nextPassage = passageDao.getFirstPassageAfterOrderInVolume(
                volumeId = currentPassage.volumeId,
                order = currentPassage.order,
                exclude = currentPassage.passageId
            ).firstOrNull()

            // 如果找不到或者它的order已经大于等于我们期望的新order，则停止循环
            if (nextPassage == null || nextPassage.order > currentOrder) {
                break
            }

            // 更新这个章节的order值
            passageDao.update(nextPassage.copy(order = currentOrder))

            // 继续处理下一个章节
            currentPassage = nextPassage
            currentOrder += 10
        }
    }

}
